import pygame
from pygame.locals import *

from shared.events import UserInput
from ui.abstract import AbstractUI
from ui.soundtrack import begin_sound


class Button:
    def __init__(self, surface, text, x, y, w, h, color, action):
        self.surface = surface
        self.text = text
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.pos = (self.x, self.y, self.w, self.h)
        self.color = color
        self.action = action
        self.buttonFont = pygame.font.Font("./res/Play-Regular.ttf", 24)
    def update(self):
        mouse = pygame.mouse.get_pos()
        click = pygame.mouse.get_pressed()
        if self.x+self.w > mouse[0] > self.x and self.y+self.h > mouse[1] > self.y:
            pygame.draw.rect(self.surface, self.color, self.pos)

            render = self.buttonFont.render(self.text, 1, (0,0,0))
            renderPos = render.get_rect()
            renderPos.center = ( (self.x+(self.w/2)), (self.y+(self.h/2)) )
            self.surface.blit(render, renderPos)

            if click[0] == 1 and self.action != None:
                self.action()
        else:
            pygame.draw.rect(self.surface, self.color, self.pos, 2)

            render = self.buttonFont.render(self.text, 1, self.color)
            renderPos = render.get_rect()
            renderPos.center = ( (self.x+(self.w/2)), (self.y+(self.h/2)) )
            self.surface.blit(render, renderPos)



class PygameUI(AbstractUI):
    """
    Note: To target a desired tile size:
    width  = tileSizeX * mazeSizeX + 200
    height = tileSizeY * mazeSizeY
    """
    def __init__(self, state, width=1200, height=1000):
        super(PygameUI, self).__init__(state)

        pygame.display.init()
        pygame.font.init()
        self.width = width
        self.height = height
        self._sideBarWidth = 200
        self._titleBarHeight = 100
        self._infoBarHeight = 300
        self._gameAreaWidth = self.width - self._sideBarWidth

        self._tileSizeX = self._gameAreaWidth // self.maze.sizeX
        self._tileSizeY = height // self.maze.sizeY

        self._resources = self._load_resources()

        self.display = pygame.display.set_mode((width, height))
        pygame.display.set_caption(self._game_name)

        self.uiEvents = []

        self._clock = pygame.time.Clock()
        self._live_frame_rate = 0

        self.titleFont = pygame.font.Font("./res/Play-Regular.ttf", 48)
        self.textFont = pygame.font.Font("./res/Play-Regular.ttf", 24)
        self.titleHeight = 90
        self.lineheight = 30

        # Generate the static part of the sidebar
        self.infoBar = self.genInfoBar()

        # Start sound.
        begin_sound()

    def wait(self):
        self._clock.tick(self._frame_rate)
        self._live_frame_rate = round(self._clock.get_fps())

    def terminate(self):
        pygame.quit()

    def poll(self):
        # Get all the events that occurred this frame.
        pygame_events = pygame.event.get()

        while self.uiEvents:
            yield self.uiEvents.pop()

        for event in pygame_events:
            if event.type == QUIT:
                self.terminate()
                yield UserInput("QUIT")
            elif event.type == KEYDOWN:
                me = self._get_event_from_char(event.unicode)
                if me is not None:
                    yield me

    def genInfoBar(self):
        infoBar = pygame.Surface((self._sideBarWidth, self._infoBarHeight))

        #Draw the title
        render = self.titleFont.render("PYMAZE", 1, (255, 255, 255))
        renderPos = render.get_rect()
        renderPos.centerx = infoBar.get_rect().centerx
        infoBar.blit(render, renderPos)

        instructions = []
        for key, desc in self._get_key_help().items():
            instructions.append("[%s] : %s" %(key, desc))
        lines = ["INSTRUCTIONS"] + instructions

        for index, line in enumerate(lines):
            render = self.textFont.render(line, 1, (255, 255, 255))
            renderPos = render.get_rect()
            #renderPos.centerx = infoBar.get_rect().centerx
            renderPos.top = index * self.lineheight + self.titleHeight
            infoBar.blit(render, renderPos)

        return infoBar

    def draw(self):
        # Generate all the elements.
        statusBar = self.genStatusBar()
        gameArea = self.genGameArea()
        overlay = self.genOverlay()

        # Blit the separate elements onto the main display.
        self.display.blit(gameArea, (0, 0))
        self.display.blit(self.infoBar, (self._gameAreaWidth, 0))
        self.display.blit(statusBar, (self._gameAreaWidth, self._infoBarHeight))
        if overlay:
            self.display.blit(overlay, (0, 0))

        pygame.display.update()  # TODO: Optimize by only updating the changed rects

    def genGameArea(self):
        gameArea = pygame.Surface((self._gameAreaWidth, self.height))
        player_loc = self.state.player.location  # (x, y)

        for y in range(self.maze.sizeY):
            for x in range(self.maze.sizeX):
                tile = Rect(x * self._tileSizeX, y * self._tileSizeY,
                            self._tileSizeX, self._tileSizeY)

                ##pygame.draw.rect(gameArea, tileColor, tile)
                if self.maze[x, y] == 0:
                    gameArea.blit(pygame.transform.scale(
                        self._resources['wall'], (self._tileSizeX, self._tileSizeY)), tile)
                else:
                    gameArea.blit(pygame.transform.scale(
                        self._resources['floor'], (self._tileSizeX, self._tileSizeY)), tile)


        for ext in self.maze.exits:
            self.draw_entity(gameArea, ext, 'goal')

        self.draw_entity(gameArea, player_loc, 'player')

        for enemy in self.state.enemies:
            self.draw_entity(gameArea, enemy.location, 'enemy')

        return gameArea

    def genStatusBar(self):
        sideBar = pygame.Surface((self._sideBarWidth, self.height))

        text = [
            ("%s FPS" % (self._live_frame_rate), (255, 255, 255)),
            ("Turbo left: {}".format(self.state.player.turbo_left), (0, 255, 255))
        ]
        if self.state.player.turbo_time:
            text.append(("TURBO ON", (255, 0, 0)))

        for i, lc in enumerate(text):
            line, colour = lc
            render = self.textFont.render(line, 1, colour)
            renderPos = render.get_rect()
            renderPos.centerx = sideBar.get_rect().centerx
            renderPos.top = renderPos.top + i * self.lineheight
            sideBar.blit(render, renderPos)

        return sideBar

    def genOverlay(self):
        if self.state.condition != "running":
            overlay = pygame.Surface((self.width, self.height))

            text = "You %s!" %(self.state.condition)

            render = self.titleFont.render(text, 1, (255, 255, 255))
            renderPos = render.get_rect()
            renderPos.center = overlay.get_rect().center
            overlay.blit(render, renderPos)

            screen = overlay.get_rect()

            Button(overlay, "Play again", screen.centerx-75, screen.centery+80, 150, 50, (255,255,255),
                self.restart).update()

            return overlay
        else:
            return None

    def restart(self):
        self.uiEvents.append(UserInput("RESTART"))

    def draw_entity(self, area, location, picture):
        player_tile = Rect(
            location[0] * self._tileSizeX, location[1] * self._tileSizeY,
            self._tileSizeX, self._tileSizeY
        )
        area.blit(
            pygame.transform.scale(
                self._resources[picture],
                (self._tileSizeX, self._tileSizeY)
            ),
            player_tile
        )

    @staticmethod
    def _load_resources():
        resources = {
            'wall': pygame.image.load("res/wall.gif"),
            'goal': pygame.image.load("res/goal.gif"),
            'player': pygame.image.load("res/player.gif"),
            'enemy': pygame.image.load("res/enemy.gif"),
            'floor': pygame.image.load("res/floor.gif")
        }

        return resources

# def start(maze):

#       while True:
#           # Get all the events that occurred this frame.
#           events = pygame.event.get()
#           for event in events:
#               # The QUIT event requires a special case, because we have to return
#               if event.type == QUIT:
#                   pygame.quit()
#                   return

#               # Otherwise, send the event to the handleEvent function.
#               handleEvent(event)
